package io.cici.cc.mybatis.lite.parse;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.w3c.dom.CharacterData;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * @author huihui
 */
@Slf4j
@Setter
@Getter
public class Node {

    private final org.w3c.dom.Node node;
    private final String name;
    private final String body;
    private final Properties attributes;
    private final Properties variables;
    private final XPathParser xpathParser;

    public Node(XPathParser xpathParser, org.w3c.dom.Node node, Properties variables) {
        this.xpathParser = xpathParser;
        this.node = node;
        this.name = node.getNodeName();
        this.variables = variables;
        this.attributes = parseAttributes(node);
        this.body = parseBodyData(node);
    }

    //============#============#============#============#============#============
    public Node evalNode(String expression) {
        return xpathParser.evalNode(node, expression);
    }

    public List<Node> evalNodeList(String expression) {
        return xpathParser.evalNodeList(node, expression);
    }

    public Node getParent() {
        org.w3c.dom.Node parent = node.getParentNode();
        if (!(parent instanceof Element)) {
            return null;
        }
        return new Node(xpathParser, parent, variables);
    }

    public Node newNode(org.w3c.dom.Node node) {
        return new Node(xpathParser, node, variables);
    }

    //============#============#============#============#============#============
    private Properties parseAttributes(org.w3c.dom.Node node) {
        Properties attributes = new Properties();
        NamedNodeMap attributeNodes = node.getAttributes();
        if (attributeNodes != null) {
            for (int i = 0; i < attributeNodes.getLength(); i++) {
                org.w3c.dom.Node attribute = attributeNodes.item(i);
                String value = FixedVariableParser.parse(attribute.getNodeValue(), variables);
                attributes.put(attribute.getNodeName(), value);
            }
        }
        return attributes;
    }

    public Boolean getBooleanAttribute(String name) {
        return getBooleanAttribute(name, null);
    }

    public Boolean getBooleanAttribute(String name, Boolean defaultValue) {
        String value = attributes.getProperty(name);
        return value == null ? defaultValue : Boolean.valueOf(value);
    }

    public Integer getIntAttribute(String name) {
        return getIntAttribute(name, null);
    }

    public Integer getIntAttribute(String name, Integer defaultValue) {
        String value = attributes.getProperty(name);
        return value == null ? defaultValue : Integer.valueOf(value);
    }

    public String getStringAttribute(String name) {
        return getStringAttribute(name, null);
    }

    public String getStringAttribute(String name, String defaultValue) {
        String value = attributes.getProperty(name);
        return value == null ? defaultValue : value;
    }

    //============#============#============#============#============#============
    public Properties getChildrenAsProperties() {
        Properties properties = new Properties();
        List<Node> childrenNodeList = getChildNodeList();
        for (Node node : childrenNodeList) {
            String name = node.getStringAttribute("name");
            String value = node.getStringAttribute("value");
            if (name != null && value != null) {
                properties.setProperty(name, value);
            }
        }
        return properties;
    }

    public List<Node> getChildNodeList() {
        List<Node> children = new ArrayList<>();
        NodeList nodeList = node.getChildNodes();
        if (nodeList != null) {
            for (int i = 0, n = nodeList.getLength(); i < n; i++) {
                org.w3c.dom.Node node = nodeList.item(i);
                if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
                    children.add(new Node(xpathParser, node, variables));
                }
            }
        }
        return children;
    }


    private String parseBodyData(org.w3c.dom.Node node) {
        String data = parseBodyData0(node);
        if (data == null) {
            NodeList nodeList = node.getChildNodes();
            for (int i = 0; i < nodeList.getLength(); i++) {
                org.w3c.dom.Node item = nodeList.item(i);
                data = parseBodyData0(item);
                if (data != null) {
                    break;
                }
            }
        }
        return data;
    }

    private String parseBodyData0(org.w3c.dom.Node node) {
        if (node.getNodeType() == org.w3c.dom.Node.CDATA_SECTION_NODE || node.getNodeType() == org.w3c.dom.Node.TEXT_NODE) {
            String data = ((CharacterData) node).getData();
            return FixedVariableParser.parse(data, variables);
        }
        return null;
    }

    public String getBody(String defaultValue) {
        return body == null ? defaultValue : body;
    }

    //============#============#============#============#============#============


}
